#!/usr/bin/perl -I ./thirds -w
# by: lilongen(lilongen@163.com, microli@sz.webex.com)
# date: 03/08/2010

use strict;
use English;
use Data::Dumper;
use Cwd;
use Assistor;
use SendMail::SendMail;	
use YAML qw(DumpFile);

sub main();
sub parseCommandLine();
sub getParam($);
sub getGloablOptions();

sub gen_report_file($$);
sub get_rdiff_log_revs_dates();
sub generateTasksQueue();
sub construct_rlog_analyse_cmd($);
sub construct_rdiff_analyse_cmd($);
sub constructCCVQueueEntry($);
sub addTasksInfoContext($);
sub constructAndYamlTasksInfo();

my $pms = {};
my $scriptName = $0;
my $cmdLine = join (" ", @ARGV);
parseCommandLine();	

my $assistor = new Assistor($pms->{cfg}, $pms->{T_SNAP});
if (!$pms->{T_SNAP}) {
	$pms->{T_SNAP} = $assistor->{'time'};
}
$assistor->set_diff_revs_dates($pms);

my $pl_path = getcwd;
my $config = $assistor->getModules();
my $modulesCvsInfo = $config->{'modules'};
my $moudles_cnt = $#{$modulesCvsInfo};
my $_H_XLOG_ = undef;
my $_X_CCV_LOG_ = $assistor->get_operate_log_file();

my $revsDirUnderT_SNAP = $assistor->get_operate_revs_dates_dir_name($pms);

exit main();

sub main() {
    #class ConfigAssistor method get_config return value is reference to hash
    my $R_TEMPLATE      = $assistor->get_report_template_file("");            
    my $R_TOP_TEMPLATE  = $assistor->get_report_template_file("top");
    
    my $REPORT          = $assistor->read_whole_file($R_TEMPLATE);
    my $REPORT_TOP      = $assistor->read_whole_file($R_TOP_TEMPLATE);

    my $date            = $assistor->get_time_date();
    my $serial          = $assistor->get_time_serial();
    
    my $old_mask = umask(0);
    mkdir("web/reports/$date");
    mkdir("web/reports/$date/$serial");
        
    mkdir("operate/$date");
    mkdir("operate/$date/$serial");
    if (!open($_H_XLOG_, ">>", $_X_CCV_LOG_)) {
		print $_H_XLOG_ "Err: Can not create/open $_X_CCV_LOG_!\n";
	}  
 
    print $_H_XLOG_ "perl -w $scriptName $cmdLine &\n\n";

    chdir("operate/$date/$serial");
    
    my $operate_path         = getcwd;

    mkdir($revsDirUnderT_SNAP);
    chdir($revsDirUnderT_SNAP);
    
    my $ld_entry 	= getcwd;
    
    my $report      = $REPORT;
    my $report_top  = $REPORT_TOP;
    my $counter     = 0;
    my $top_url     = "";
    if ($pms->{mode} == 0) {
    	$top_url = $assistor->get_branch_report_top_file($revsDirUnderT_SNAP, 0);
    } else {
        $top_url = $assistor->get_rdiff_report_top_file($revsDirUnderT_SNAP, 0);
    }    
    
    my $main_url    = "";
    
    $report =~ s/#TOP#/$top_url/;
    
    for (my $j = 0; $j <= $moudles_cnt; $j++) {
    	my $module = $modulesCvsInfo->[$j];
        my $module_id = $module->{id};

        if ($pms->{mids} eq "*" || index(",$pms->{mids},", ",$module_id,") != -1) {
        	$counter ++;
        } else {
        	next;
        }
        
        mkdir($module_id);

        if ($pms->{mode} == 0) {
	        mkdir($module_id . "/rev_files");
	        mkdir($module_id . "/1.1");
	        mkdir($module_id . "/head");
	              	
        	$main_url = $assistor->get_branch_module_report_main_user_file($revsDirUnderT_SNAP, $module_id, 0);
        } else {
	        $main_url = $assistor->get_rdiff_module_report_main_group_file($revsDirUnderT_SNAP, $module_id, 0);
	    }
	    
        if ($counter == 1) {
            $report =~ s/#MAIN#/$main_url/;
          
        }
        
        #$report_top =~ s/((<div class="tabbertab" title=")#TITLE(" id=")#URL#("><\/div>))/$2$module_id$3$main_url$4\n$1/;
        $report_top =~ s/((<li><a id=")#URL#(" href="#tab-c">)#TITLE#(<\/a><\/li>))/$2$main_url$3$module_id$4\n$1/;
    }
    #Add to adjust top height according to modules amount
    my $top_height = 40;
    if ($counter > 20) {
    	$top_height = 100;	
    } elsif ($counter > 10) {
    	$top_height = 70;	
    }
    $report =~ s/#HEIGHT#/$top_height/;    
    #End
    
    $report_top =~ s/((<li><a id=")#URL#(" href="#tab-c">)#TITLE#(<\/a><\/li>))//;
    chdir($pl_path);
    
    my $reportFrames = "";
    my $reportTop = "";
    if ($pms->{mode} == 0) {
        $reportFrames 	= $assistor->get_branch_report_file($revsDirUnderT_SNAP);
        $reportTop 		= $assistor->get_branch_report_top_file($revsDirUnderT_SNAP);
    } else {
        $reportFrames 	= $assistor->get_rdiff_report_file($revsDirUnderT_SNAP);
        $reportTop 		= $assistor->get_rdiff_report_top_file($revsDirUnderT_SNAP);
    }    
    gen_report_file($reportFrames, \$report);
    gen_report_file($reportTop, \$report_top);
    
    chdir($operate_path);
    chdir($pl_path);
    
    if (defined($_H_XLOG_)) {
        close($_H_XLOG_);
    }
    umask($old_mask);

	constructAndYamlTasksInfo();
	
	my $flagInBG = $pms->{fromCGI} == 1 ? "&" : "";
	my $runTaskManager = "perl -w task.manager.pl \"$pms->{T_SNAP}\" $flagInBG";
    system($runTaskManager);
    
    return 0;
}

sub constructAndYamlTasksInfo() {
    my $tasksQueue = generateTasksQueue();
	my $tasksInfo = {};
	$tasksInfo->{queue} = $tasksQueue;
	addTasksInfoContext($tasksInfo);

	my $queueFile = $assistor->get_operate_cvs_task_queue_file();	
    DumpFile($queueFile, $tasksInfo);	
}

sub addTasksInfoContext($) {
	my $tasksInfo = $_[0];
    my $htmlReportURL = $assistor->getHtmlReportURL($pms->{mode}, $revsDirUnderT_SNAP);
    my $plainReportURL = $assistor->getPlainReportURL();
	my $log_entry = constructCCVQueueEntry($htmlReportURL);

	$tasksInfo->{context} = {};
	$tasksInfo->{context}->{fromCGI} 			= $pms->{fromCGI};

	$tasksInfo->{context}->{reportMode}			= $pms->{mode};
	$tasksInfo->{context}->{revsDirUnderT_SNAP}	= $revsDirUnderT_SNAP;

	$tasksInfo->{context}->{htmlReportURL} 		= $htmlReportURL;
	$tasksInfo->{context}->{plainReportURL} 	= $plainReportURL;
	$tasksInfo->{context}->{queryLogEntry} 		= $log_entry;	
}

sub constructCCVQueueEntry($) {
	my $htmlReportURL = $_[0];
    #Log entry example
    #ecc<|>N/A<|>N/A<|>2007-10-23 05:28:35<|>main<|>http://172.16.251.245:80/cvschangeviewer/reports/2007-10-23/052835/main-users_details.html
	
    my $history = "";
    my $dt = $assistor->get_friendly_time();
    my $LOG_SP = "<|>";
    my $modules = $pms->{mids};

    $modules =~ s/^,//;
    $modules =~ s/,{2,}$//g;
	
	if ($pms->{mode} == 0) {
	    $history = sprintf("%s$LOG_SP%s$LOG_SP%s$LOG_SP%s", 
	                        $modules,
	                        ($pms->{date} eq "" ? "N/A" : $pms->{date}), 
	                        ($pms->{wids} eq "" ? "N/A" : $pms->{wids}),
	                        $dt);
    } else {
	    $history = sprintf("%s$LOG_SP%s$LOG_SP%s$LOG_SP%s", 
                    $modules,
                    "", 
                    "",
                    $dt);
    }
    
    my $revs_dates  = ($pms->{mode} == 0 ? $revsDirUnderT_SNAP : get_rdiff_log_revs_dates());
    my $log_entry = sprintf("%s$LOG_SP%s$LOG_SP%s$LOG_SP%s\n",
                              $pms->{mode},
                              $history,
							  $revs_dates,                            
                              $htmlReportURL);
                              
	return $log_entry;
}

sub gen_report_file($$) {
    my $file_name = $_[0];
    my $file_content = $_[1];
    my $h_file;
    
    if (!open($h_file, ">>", $file_name)) {
		print $_H_XLOG_ "Err: Can not create/open $file_name!\n";
		
		return 1;
	}         
    
    print $h_file $$file_content;
    close($h_file);
    
    return 0;
}

sub get_rdiff_log_revs_dates() {
	my $revs_dates_log = "";
	if ($pms->{dfDates} ne "") {
		if ($pms->{d1} eq "" || $pms->{d2} eq "") {
			$revs_dates_log = "Date1: ";
			$revs_dates_log .= ($pms->{d1} eq "" ? $pms->{d2} : $pms->{d1});
			$revs_dates_log .= " Date2: HEAD(MAIN)"
		} else {
			$revs_dates_log = "Date1: $pms->{d1} Date2: $pms->{d2}";
			
		}
	} 
	
	if ($pms->{dfRevs} ne "") {
		if ($pms->{r1} eq "" || $pms->{r2} eq "") {
			$revs_dates_log = "Rev1: ";
			$revs_dates_log .= ($pms->{r1} eq "" ? $pms->{r2} : $pms->{r1});
			$revs_dates_log .= " Rev2: HEAD(MAIN)"
		} else {
			$revs_dates_log = "Rev1: $pms->{r1} Rev2: $pms->{r2}";
			
		}
	} 	   	
 		
	return 	$revs_dates_log;
}

sub generateTasksQueue() {
	my $tasksQueue = [];
    for (my $j = 0; $j <= $moudles_cnt; $j++) {
    	my $module = $modulesCvsInfo->[$j];
        my $module_id = $module->{id};
        
        if (!($pms->{mids} eq "*" || index(",$pms->{mids},", ",$module_id,") != -1)) {
        	next;	
        }
		        
        my $cvs_module = $module->{module};
        my $cvs_log_file    = $module->{'log'};
        my $cvs_diff_file   = $module->{'diff'};
                
        my $cvsroot = $assistor->get_module_cvsroot($module);
        my $cvsrootNoUID = $assistor->get_module_cvsroot_without_uid($module);
        my $operatePath = $assistor->get_operate_path($assistor->get_operate_revs_dates_dir_name($pms));
		
		my $moduleTasks = [];
		if ($pms->{mode} == 0) { #rlog
		    my $revRestrict = (uc($pms->{rev}) eq "MAIN") ? "" : "-r$pms->{rev}";
		    my $dateRestrict = ($pms->{date} eq "") ? "" : "-d\"$pms->{date}\"";
		    
		    #get rlog
		    my $taskrLog = {};
	    	$taskrLog->{cmd} = "cvs -Q -d $cvsroot rlog -N $revRestrict $dateRestrict \"$cvs_module\" > $cvs_log_file 2>&1";
	    	$taskrLog->{cvsMode} = $module->{'access_mode'};#pserver, ext
			$taskrLog->{workPath} = $operatePath;
			$taskrLog->{title} = "<b>$module_id</b>";
			$taskrLog->{desc} = "$cvs_module - $cvsrootNoUID";
			push(@{$moduleTasks}, $taskrLog);
	    	#End
			
			#check out 1.1 version 
		    if ($pms->{rev} eq "MAIN") {
		    	my $taskCO11 = {};
		    	
		    	$taskCO11->{cmd} = "cvs -Q -d $cvsroot co -r1.1 \"$cvs_module\" 2>&1";
		    	$taskCO11->{cvsMode} = $module->{'access_mode'};
				$taskCO11->{workPath} = $operatePath . $module_id . "/1.1";
				$taskCO11->{title} = "";
				$taskCO11->{desc} = "";
				push(@{$moduleTasks}, $taskCO11);		    	
		    }
		    #End
		    
		    #check out latest
		    if ($pms->{gopt}->{graph}) {
		    	my $taskCO = {};
		    	
		    	$taskCO->{cmd} = "cvs -Q -d $cvsroot co $revRestrict \"$cvs_module\" 2>&1";
		    	$taskCO->{cvsMode} = $module->{'access_mode'};
				$taskCO->{workPath} = $operatePath . $module_id . "/head";
				$taskCO->{title} = "";
				$taskCO->{desc} = "";
				push(@{$moduleTasks}, $taskCO);	
		    }
		    #End
		    
			my $taskAnalyse = {};
			$taskAnalyse->{cmd} = construct_rlog_analyse_cmd($module_id);		
			$taskAnalyse->{workPath} = "";
			$taskAnalyse->{title} = "";
			$taskAnalyse->{desc} = "";
			push(@{$moduleTasks}, $taskAnalyse);
			
		    #stat. module files when need graph
		    if ($pms->{gopt}->{graph}) {
		    	my $modulePath = $assistor->get_module_co_head_path($revsDirUnderT_SNAP, $module_id);

		    	my $taskStatFiles = {};
		    	$taskStatFiles->{cmd} = "perl -w stat.files.pl \"$pms->{T_SNAP}\" \"$modulePath\"";
				$taskStatFiles->{workPath} = "";
				$taskStatFiles->{title} = "";
				$taskStatFiles->{desc} = "";
				push(@{$moduleTasks}, $taskStatFiles);
				
		    	my $taskDrawGraph = {};
		    	$taskDrawGraph->{cmd} = "perl -w draw.graph.pl \"$modulePath\"";
				$taskDrawGraph->{workPath} = "";
				$taskDrawGraph->{title} = "";
				$taskDrawGraph->{desc} = "";
				push(@{$moduleTasks}, $taskDrawGraph);				
		    }
		    #End			
		    
		} else {#rdiff
			my $revs = "";
			my $dates = "";
			if ($pms->{r1} ne "" || $pms->{r2} ne "") {
				$revs = (($pms->{r1} ne "") ? "-r$pms->{r1}" : "") . (($pms->{r2} ne "") ? " -r$pms->{r2}" : "");
			} else {
				$dates = (($pms->{d1} ne "") ? "-D$pms->{d1}" : "") . (($pms->{d2} ne "") ? " -D$pms->{d2}" : "");
			}
			my $taskrDiff = {};
	    	$taskrDiff->{cmd} = "cvs -Q -d $cvsroot rdiff -u $revs $dates \"$cvs_module\" > $cvs_diff_file 2>&1";
	    	$taskrDiff->{cvsMode} = $module->{'access_mode'};
			$taskrDiff->{workPath} = $operatePath;
			$taskrDiff->{title} = "<b>$module_id</b>";
			$taskrDiff->{desc} = "$cvs_module - $cvsrootNoUID";
			push(@{$moduleTasks}, $taskrDiff);
			
			my $taskAnalyse = {};
			$taskAnalyse->{cmd} = construct_rdiff_analyse_cmd($module_id);		
			$taskAnalyse->{workPath} = "";
			$taskAnalyse->{title} = "";
			$taskAnalyse->{desc} = "";
			push(@{$moduleTasks}, $taskAnalyse);
		}
		
		push(@{$tasksQueue}, $moduleTasks);
    }
    
    return $tasksQueue;
}

sub construct_rlog_analyse_cmd($){
    my $mid = $_[0];

    my $cmd = sprintf("perl -w \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"", 
                        $assistor->{LOG_ANALYSER},
                        "-f" . $pms->{cfg},
                        "-t" . $pms->{T_SNAP},
                        "-r" . $pms->{rev},
                        "-m" . $mid,
                        "-d" . $pms->{date},
                        "-w" . $pms->{wids},
                        "-gm".  $pms->{gopt}->{graph},
                        "-arm". $pms->{gopt}->{allRevs},
                        "-sbm". $pms->{gopt}->{statBin},
                        "-sbl". $pms->{gopt}->{statBinLines},
                        "-nsd". $pms->{gopt}->{notStatDeleted});
    
    return $cmd;
}

sub construct_rdiff_analyse_cmd($) {
	my $mid = $_[0];
    my $cmd = sprintf("perl -w \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"", 
                        $assistor->{DIFF_ANALYSER},
                        "-f"  . $pms->{cfg},
                        "-t"  . $pms->{T_SNAP},
                        "-r1" . $pms->{r1},
                        "-r2" . $pms->{r2},
                        "-D1" . $pms->{d1},
                        "-D2" . $pms->{d2},
                        "-m"  . $mid);
    
	return $cmd;
}

sub getGloablOptions() {
	my $bitGraph = 0;
	my $bitAllRevs = 1;
	my $bitStatBin = 2;
	my $bitStatBinLines = 3;
	my $bitNotStatDeleted = 4;
	
	$pms->{gopt} = {};

	$pms->{gopt}->{graph} 			= (($pms->{GO} >> $bitGraph) & 1) ? 1 : 0;
	$pms->{gopt}->{allRevs} 		= (($pms->{GO} >> $bitAllRevs) & 1) ? 1 : 0;
	$pms->{gopt}->{statBin} 		= (($pms->{GO} >> $bitStatBin) & 1) ? 1 : 0;
	$pms->{gopt}->{statBinLines} 	= (($pms->{GO} >> $bitStatBinLines) & 1) ? 1 : 0;
	$pms->{gopt}->{notStatDeleted} 	= (($pms->{GO} >> $bitNotStatDeleted) & 1) ? 1 : 0;
}

sub parseCommandLine() {
	$pms->{fromCGI} 	= getParam("-FC");
    $pms->{T_SNAP} 		= getParam("-T");
    $pms->{cfg} 		= getParam("-f");
    $pms->{mode} 		= getParam("-R");
    $pms->{mids} 		= getParam("-m");
    $pms->{GO} 			= getParam("-GO");
  	
  	if ($pms->{mode} == 0) {
  		$pms->{rev} 	= getParam("-r");
  		$pms->{date} 	= getParam("-d");
  		$pms->{wids} 	= getParam("-w");
  		
  		if (!$pms->{rev}) {
  			$pms->{rev} = "MAIN";
  		}
  	} else {
  		$pms->{r1} 		= getParam("-r1");
  		$pms->{r2} 		= getParam("-r2");
  		$pms->{d1} 		= getParam("-D1");
  		$pms->{d2} 		= getParam("-D2");  		  		
  	}
  	
  	$pms->{fromCGI} 	= ($pms->{fromCGI} ne "" ? $pms->{fromCGI} : "0");
  	
  	getGloablOptions();
}

sub getParam($) {
	my $indicator = $_[0];
	
    if ($cmdLine =~ m/(^|\s)$indicator([^\s]+)/) {
        return $2;   
    } else {
    	return "";
    } 	
}
